table of contents
GETRLIMIT(2) | Руководство программиста Linux | GETRLIMIT(2) |
ИМЯ¶
getrlimit, setrlimit, prlimit - считывает/устанавливает ограничения использования ресурсов
ОБЗОР¶
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit
*rlim);
int setrlimit(int resource, const struct rlimit
*rlim);
int prlimit(pid_t pid, int
resource, const struct rlimit
*new_limit,
struct rlimit *old_limit);
Требования
макроса
тестирования
свойств
для glibc (см.
feature_test_macros(7)):
prlimit(): _GNU_SOURCE && _FILE_OFFSET_BITS == 64
ОПИСАНИЕ¶
Системные вызовы getrlimit() и setrlimit(), соответственно, получают и устанавливают ограничения использования ресурсов. Каждому ресурсу назначается мягкое и жёсткое ограничение, определяемое структурой rlimit:
struct rlimit {
rlim_t rlim_cur; /* мягкое ограничение */
rlim_t rlim_max; /* жёсткое ограничение (максимум для rlim_cur) */ };
Мягким ограничением является значение, принудительно устанавливаемое ядром для соответствующего ресурса. Жёсткое ограничение работает как максимальное значение для мягкого ограничения: непривилегированные процессы могут определять только свои мягкие ограничения в диапазоне от 0 до жёсткого ограничения, то есть однозначно меньше жёсткого ограничения. Привилегированные процессы (в Linux: имеющие мандат CAP_SYS_RESOURCE) могут устанавливать произвольные значения в любых пределах.
Значение RLIM_INFINITY означает отсутствие ограничений для ресурса (в структуре, возвращаемой getrlimit() и в структуре, передаваемой в setrlimit()).
Значение resource должно быть одним из:
- RLIMIT_AS
- Максимальный размер виртуальной памяти (адресного пространства) процесса в байтах. Учитывается в вызовах brk(2), mmap(2) и mremap(2), которые завершатся с ошибкой ENOMEM, если будет превышено это ограничение. Также завершится с ошибкой автоматическое расширение стека (и будет сгенерирован сигнал SIGSEGV, по которому завершится процесс, если не было создано с помощью sigaltstack(2) альтернативного стека). Так как значение имеет тип long, на машинах с 32-битным long максимальное значение ограничения будет около 2 ГиБ, или этот ресурс не ограничивается.
- RLIMIT_CORE
- Максимальный размер файла core. Если значение равно 0, то файлы core не создаются. Если значение больше нуля, то создаваемые дампы обрезаются до этого размера.
- RLIMIT_CPU
- Время выполнения на ЦП в секундах. Когда процесс достигает своего мягкого ограничения, то ему отправляется сигнал SIGX CPU. Действием по умолчанию для этого сигнала является завершение процесса. Однако, этот сигнал может быть перехвачен, и обработчик может передать управление в основную программу. Если процесс продолжает потреблять процессорное время, то ему будет отправляться SIGXCPU раз в секунду до тех пор, пока не будет достигнуто жёсткое ограничение, и тогда процессу будет послан сигнал SIGKILL. (Последний пункт описывает поведение Linux. В разных реализациях действия над потребляющими процессорное время после прохождения мягкого ограничения процессами различаются. Переносимые приложения, где требуется перехват сигнала, должны выполнять корректное завершение процесса после первого получения SIGXCPU.)
- RLIMIT_DATA
- Максимальный размер сегмента данных процесса (инициализированные данные, неинициализированные данные, куча). Это ограничение учитывается в вызовах brk(2) и sbrk(2), которые завершатся с ошибкой ENOMEM при достижении мягкого ограничения этого ресурса.
- RLIMIT_FSIZE
- Максимальный размер файлов, создаваемых процессом. Попытки расширить файл сверх этого ограничения приведёт к доставке сигнала SIGXFSZ. По умолчанию по этому сигналу процесс завершается, но процесс может перехватить этот сигнал и в этом случае выполнявшийся системный вызов (например, write(2), truncate(2)) завершится с ошибкой EFBIG.
- RLIMIT_LOCKS (только в ранних версиях Linux 2.4)
- Ограничение на общее количество блокировок flock(2) и аренд fcntl(2), которое может установить процесс.
- RLIMIT_MEMLOCK
- Максимальное количество байт памяти, которое может быть заблокировано в ОЗУ. В целях эффективности это ограничение округляется в меньшую сторону до ближайшего значения, кратного размеру системной страницы. Это ограничение учитывается в mlock(2) и mlockall(2) и в mmap(2) при операции MAP_LOCKED. Начиная с Linux 2.6.9, оно также учитывается в shmctl(2) при операции SHM_LOCK, где определяет максимальное количество байт всех общих сегментов памяти (см. shmget(2)), которые могут быть заблокированы вызывающим процессом с реальным идентификатором пользователя. Блокировки по операции SHM_LOCK у shmctl(2) учитываются отдельно от попроцессных блокировок памяти, устанавливаемых mlock(2), mlockall(2) и mmap(2) операцией MAP_LOCKED; процесс может заблокировать пространство до этого значения заданного ограничения байт в каждой из этих двух категорий. В ядрах Linux до версии 2.6.9 этим ограничением контролировалось количество памяти, которое можно было блокировать привилегированному процессу. Начиная с Linux 2.6.9 это ограничение снято и теперь это ограничение управляет количеством памяти, которое может блокировать непривилегированный процесс.
- RLIMIT_MSGQUEUE (начиная с Linux 2.6.8)
- Ограничение
на
количество
байт,
которое
может
выделяться
для
очередей
сообщений
POSIX для
вызывающего
процесса с
реальным
идентификатором
пользователя.
Это
ограничение
учитывается
в mq_open(3).
Каждая
очередь
сообщений,
которую
создаёт
пользователь,
учитывается
(пока не
будет
удалена) в
формуле:
где attr — структура mq_attr, указанная в четвёртом аргументе mq_open(3).
bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
attr.mq_maxmsg * attr.mq_msgsizeПервое слагаемое в формуле, sizeof(struct msg_msg *) (4 байта в Linux/i386), нужно, чтобы пользователь не смог создать бесконечное количество сообщений нулевой длины (для таких сообщений, тем не менее, потребляется системная память для учёта использования системных ресурсов).
- RLIMIT_NICE (начиная с Linux 2.6.12, см. ДЕФЕКТЫ далее)
- Определяет максимум, до которого может быть увеличено значение nice с помощью setpriority(2) или nice(2). Действительный максимум значения nice высчитывается по формуле: 20 - rlim_cur. (Так пришлось поступить из-за того, что отрицательные числа нельзя указывать в значениях ограничений ресурсов, так как они, обычно, имеют специальное предназначение. Например, RLIM_INFINITY, обычно равно -1.)
- RLIMIT_NOFILE
- Определяет значение, на 1 больше максимального количества дескрипторов файлов, которое может открыть этот процесс. Попытки (open(2), pipe(2), dup(2) и т.п.) превысить это ограничение приведут к ошибке EMFILE. (Раньше это ограничение в BSD называлось RLIMIT_OFILE.)
- RLIMIT_NPROC
- Максимальное количество процессов (или, более точно для Linux, нитей), которое может создать вызывающий процесс с реальным идентификатором пользователя. При превышении этого ограничения fork(2) завершается с ошибкой EAGAIN.
- RLIMIT_RSS
- Максимальное ограничение (в страницах) на число постоянных страниц процесса (числа виртуальных страниц, постоянно присутствующих в ОЗУ). Это ограничение учитывается только начиная с версии Linux 2.4.x, x < 30, и только в вызовах madvise(2) со значением MADV_WILLNEED.
- RLIMIT_RTPRIO (начиная с Linux 2.6.12, см. ДЕФЕКТЫ)
- Определяет максимум для приоритета реального времени, который можно установить для процесса с помощью sched_setscheduler(2) и sched_setparam(2).
- RLIMIT_RTTIME (начиная с Linux 2.6.25)
- Определяет
ограничение
(в
микросекундах)
на
количество
времени ЦП,
которое
процесс
может быть
запланирован
выполняться
в условиях
реального
времени
без
выполнения
блокирующего
системного
вызова. Для
работы
ограничения,
всякий раз
когда
процесс
делает
блокирующий
системный
вызов
счётчик
использованного
времени ЦП
сбрасывается
в ноль.
Счётчик
времени ЦП
не
сбрасывается,
если
процесс
продолжает
пытаться
использовать
ЦП, но был
вытеснен,
его
выделенное
время на
исполнение
истекло
или он
вызвал sched_yield(2).
При достижении мягкого ограничения процессу посылается сигнал SIGXCPU. Если процесс перехватил сигнал, проигнорировал его и продолжает потреблять время ЦП, то раз в секунду будет генерироваться сигнал SIGXCPU до тех пор, пока не будет достигнуто жёсткое ограничение, и процессу не будет послан сигнал SIGKILL.
Это ограничение предназначено для предотвращения блокировки системы вышедшими из под контроля процессами реального времени.
- RLIMIT_SIGPENDING (начиная с Linux 2.6.8)
- Определяет ограничение на количество сигналов, которые могут быть поставлены в очередь вызывающего процесса с реальным пользовательским идентификатором. При проверке ограничения учитываются обычные сигналы и сигналы реального времени. Однако ограничение учитывается только в sigqueue(3); всегда возможно использовать kill(2) для постановки в очередь любого сигнала, которого ещё нет в очереди процесса.
- RLIMIT_STACK
- Максимальный
размер
стека
процесса в
байтах. При
достижении
этого
ограничения
генерируется
сигнал SIGSEGV.
Для
обработки
этого
сигнала
процесс
должен
использовать
альтернативный
стек
сигналов
(sigaltstack(2)).
Начиная с Linux 2.6.23, это ограничение также определяет количество места, используемого для аргументов командной строки процесса и его переменных окружения; подробней об этом смотрите в execve(2).
prlimit()¶
Системный вызов prlimit(), который есть только в Linux объединяет и расширяет функции setrlimit() и getrlimit(). Он может использоваться для задания и получения ограничений ресурсов произвольного процесса.
Аргумент resource имеет тот же смысл что и в setrlimit() и getrlimit().
Если значение аргумента new_limit не равно NULL, то структура rlimit, на которую он указывает, используется для задания новых значений мягкий и жёстких ограничений для resource. Если значение аргумента old_limit не равно NULL, то успешный вызов prlimit() помещает текущие значения мягких и жёстких ограничений для resource в структуру rlimit, на которую указывает old_limit.
В аргументе pid задаётся идентификатор процесса с которым работает вызыв. Если pid равно 0, то вызов применяется к вызывающему процессу. Для установки и получения ресурсов не своего процесса, вызывающий должен иметь мандат CAP_SYS_RESOURCE или реальный, эффективный и сохранённый идентификатор пользователя процесса назначения должен совпадать с реальным идентификатором пользователя вызывающего и реальный, эффективный и сохранённый идентификатор группы процесса назначения должны совпадать с реальным идентификатором группы вызывающего.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
ОШИБКИ¶
- EFAULT
- Аргумент-указатель указывает за пределы доступного адресного пространства.
- EINVAL
- Указано некорректное значение resource; или для setrlimit() или prlimit(): rlim->rlim_cur больше чем rlim->rlim_max.
- EPERM
- Непривилегированный процесс пытался увеличить жёсткое ограничение; для этого требуется мандат CAP_SYS_RESOURCE. Или вызывающий увеличить жёсткое ограничение RLIMIT_NOFILE, превышая текущий максимум ядра (NR_OPEN). Или вызывающий процесс не имеет прав для назначения ограничений процессу, указанному в pid.
- ESRCH
- Не удалось найти процесс с идентификатором, указанном в pid.
ВЕРСИИ¶
Системный вызов prlimit() появился в Linux 2.6.36. Поддержка в glibc доступна начиная с версии 2.13.
СООТВЕТСТВИЕ СТАНДАРТАМ¶
getrlimit(), setrlimit(): SVr4, 4.3BSD,
POSIX.1-2001.
prlimit(): только в
Linux.
Ограничение RLIMIT_MEMLOCK и RLIMIT_NPROC появились из BSD и их нет в POSIX.1-2001; они есть в BSD и Linux, но реализации несколько различны. Ограничение RLIMIT_RSS появилось из BSD и его нет в POSIX.1-2001; тем не менее оно есть в большинстве реализаций. Ограничения RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_RTTIME и RLIMIT_SIGPENDING есть только в Linux.
ЗАМЕЧАНИЯ¶
Дочерний процесс, созданный fork(2), наследует ограничения ресурсов родителя. Ограничения ресурсов сохраняются при execve(2).
Ограничения ресурсов интерпретатора командной строки можно устанавливать с помощью встроенной команды ulimit (limit в csh(1)). Ограничения ресурсов интерпретатора наследуются дочерними процессами, которые он создаёт при выполнении команд.
В старых системах была функция vlimit() с подобным setrlimit() назначением. Для обратной совместимости в glibc также есть функция vlimit(). Во всех новых приложениях должен быть использован setrlimit().
ПРИМЕР¶
Представленная ниже программа показывает использование prlimit().
#define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <sys/resource.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0) int main(int argc, char *argv[]) {
struct rlimit old, new;
struct rlimit *newp;
pid_t pid;
if (!(argc == 2 || argc == 4)) {
fprintf(stderr, "Использование: %s <pid> [<новое-мягкое-ограничение> "
"<новое-жёсткое-ограничение>]\n", argv[0]);
exit(EXIT_FAILURE);
}
pid = atoi(argv[1]); /* PID процесса назначения */
newp = NULL;
if (argc == 4) {
new.rlim_cur = atoi(argv[2]);
new.rlim_max = atoi(argv[3]);
newp = &new;
}
/* Установить ограничение на время ЦП процесса назначения;
получить и показать предыдущее ограничение */
if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1)
errExit("prlimit-1");
printf("Previous limits: soft=%lld; hard=%lld\n",
(long long) old.rlim_cur, (long long) old.rlim_max);
/* Получить и показать новое ограничение времени ЦП */
if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1)
errExit("prlimit-2");
printf("Новые ограничения: мягкое=%lld; жёсткое=%lld\n",
(long long) old.rlim_cur, (long long) old.rlim_max);
exit(EXIT_FAILURE); }
ДЕФЕКТЫ¶
В старых ядрах Linux сигналы SIGXCPU и SIGKILL, посылаемые когда у процесса обнаруживается достижение мягкого и жёсткого ограничения RLIMIT_CPU, доставляются на одну секунду (ЦП) позднее чем это должно быть. Это исправлено в ядре версии 2.6.8.
В ядрах 2.6.x до версии 2.6.17, ограничение RLIMIT_CPU равное 0, неправильно воспринималось как «без ограничения» (подобно RLIM_INFINITY). Начиная с Linux 2.6.17, установка ограничения в 0 действует, но реально обрабатывается как ограничение в 1 секунду.
Из-за дефекта ядра RLIMIT_RTPRIO не работает в версии 2.6.12; это исправлено в ядре 2.6.13.
В ядре 2.6.12 было несоответствие в единицу между диапазонами приоритетов, возвращаемых getpriority(2) и RLIMIT_NICE. Это приводило к тому, что реальный максимум значения nice вычислялся как 19 - rlim_cur. Исправлено в ядре 2.6.13.
В ядрах до 2.4.22 не определялась ошибка EINVAL в setrlimit(), если значение rlim->rlim_cur было больше rlim->rlim_max.
СМОТРИТЕ ТАКЖЕ¶
dup(2), fcntl(2), fork(2), getrusage(2), mlock(2), mmap(2), open(2), quotactl(2), sbrk(2), shmctl(2), malloc(3), sigqueue(3), ulimit(3), core(5), capabilities(7), signal(7)
2011-09-10 | Linux |